﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MobilnyDostawca.Enums;
using MobilnyDostawca.ViewModels;

namespace MobilnyDostawca.Repositories
{
    public static class Repository
    {
        private static MobilnyDostawcaDBLEntities dbEntities = new MobilnyDostawcaDBLEntities();
       // private static MobilnyDostawcaDBEntities dbEntities = new MobilnyDostawcaDBEntities();

        #region Deliverers
        public static IEnumerable<Dostawcy> GetAllDeliverers()
        {
            return dbEntities.Dostawcy.Select(d => d).ToList();
        }

        public static Dostawcy GetDelivererByID(int id)
        {
            return dbEntities.Dostawcy.Find(id);
        }

        public static IEnumerable<SelectListItem> GetAllDeliverersSelectItemList()
        {
            var dostawcy = GetAllDeliverers();
            foreach (var item in dostawcy)
            {
                yield return new SelectListItem() { Text = string.Format("{0} {1}", item.Imie, item.Nazwisko), Value = item.ID.ToString() };
            }
        }

        public static bool IsDelivererWithoutSubregion(int id) 
        {
            return GetSubregionsForDeliverer(id).Count() == 0;
        }

        public static IEnumerable<Dostawcy> GetPossibleDeliverersForSubregion(int id)
        {
            Regiony region = GetSubregionByID(id).Regiony;

            return dbEntities.Dostawcy.Where(d => (d.Subregiony.Count > 0 && d.Subregiony.FirstOrDefault().Region == region.ID) || d.Subregiony.Count == 0);
        }

        public static Dictionary<Dostawcy, int> GetDelivererResult(DelivererOpinion opinion) 
        {
            Statusy status = GetStatusOfDeliveredParcel();

            Dictionary<Dostawcy, int> deliverersDictionary = new Dictionary<Dostawcy,int>();

            foreach(var deliverer in dbEntities.Dostawcy)
            {
                deliverersDictionary.Add(deliverer, dbEntities.Przesylki.Where(p => p.Status == status.ID && p.Dostawca == deliverer.ID).Count());
            }

            switch (opinion) 
            { 
                case DelivererOpinion.TheWorst:
                    return GetTheWorstDeliverers(deliverersDictionary);
                
                default:
                    return GetTheBestDeliverers(deliverersDictionary);
            }
                                    
        }

        public static Dictionary<Dostawcy, int> GetDelivererResultWithDateConditions(DelivererOpinion opinion, DateTime start)
        {
            Statusy status = GetStatusOfDeliveredParcel();

            Dictionary<Dostawcy, int> deliverersDictionary = new Dictionary<Dostawcy, int>();

            foreach (var deliverer in dbEntities.Dostawcy)
            {
                deliverersDictionary.Add(deliverer, dbEntities.Przesylki.Where(p => p.Status == status.ID && p.Dostawca == deliverer.ID
                    && p.Timestamp >= start).Count());
            }

            switch (opinion)
            {
                case DelivererOpinion.TheWorst:
                    return GetTheWorstDeliverers(deliverersDictionary);

                default:
                    return GetTheBestDeliverers(deliverersDictionary);
            }

        }

        private static Dictionary<Dostawcy, int> GetTheWorstDeliverers(Dictionary<Dostawcy, int> deliverersDictionary)
        {
            Dictionary<Dostawcy, int> minDic = new Dictionary<Dostawcy, int>();
            foreach (var deliverer in deliverersDictionary)
            {
                if (minDic.Count == 0)
                {
                    minDic.Add(deliverer.Key, deliverer.Value);
                }
                else
                {
                    if (deliverer.Value < minDic.First().Value)
                    {
                        minDic.Clear();
                        minDic.Add(deliverer.Key, deliverer.Value);
                    }
                    else if (deliverer.Value == minDic.First().Value)
                    {
                        minDic.Add(deliverer.Key, deliverer.Value);
                    }
                }
            }
            return minDic;
        }

        private static Dictionary<Dostawcy, int> GetTheBestDeliverers(Dictionary<Dostawcy, int> deliverersDictionary)
        {
            Dictionary<Dostawcy, int> maxDic = new Dictionary<Dostawcy, int>();
            foreach (var deliverer in deliverersDictionary)
            {
                if (maxDic.Count == 0)
                {
                    maxDic.Add(deliverer.Key, deliverer.Value);
                }
                else
                {
                    if (deliverer.Value > maxDic.First().Value)
                    {
                        maxDic.Clear();
                        maxDic.Add(deliverer.Key, deliverer.Value);
                    }
                    else if (deliverer.Value == maxDic.First().Value)
                    {
                        maxDic.Add(deliverer.Key, deliverer.Value);
                    }
                }
            }
            return maxDic;
        }
        #endregion

        #region Parcels
        public static IEnumerable<Przesylki> GetAllParcels()
        {
            return dbEntities.Przesylki.Select(p => p).ToList();
        }

        public static int GetNumberOfAllParcels() 
        {
            return GetAllParcels().Count();
        }

        public static int GetNumberOfParcelsWithDateConditions(DateTime start)
        {
            return dbEntities.Przesylki.Where(p => p.Timestamp >= start).Count();
        }

        public static int GetNumberOfDeliveredParcelsWithDateConditions(DateTime start)
        {
            Statusy status = GetStatusOfDeliveredParcel();
            return dbEntities.Przesylki.Where(p => p.Status == status.ID && p.Timestamp >= start).Count();
        }

        public static int GetNumberOfDeliveredParcels()
        {
            Statusy status = GetStatusOfDeliveredParcel();
            return dbEntities.Przesylki.Where(p => p.Status == status.ID).Count();
        }

        public static Przesylki GetParcelByID(int id)
        {
            return dbEntities.Przesylki.Find(id);
        }

        /// <summary>
        /// Zwraca przesyłki które aktualnie są obsługiwane przez Dostawcę
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static IEnumerable<Przesylki> GetActualParcelsForDeliverer(int id)
        {
            return dbEntities.Przesylki.Where(p => p.Dostawca == id).OrderBy(i => i.ID);
        }

        /// <summary>
        /// Zwraca przesyłki które SĄ bądź BĘDĄ obsługiwane przez dostawcę
        /// </summary>
        /// <param name="id">id dostawcy</param>
        /// <returns></returns>
        public static IEnumerable<Przesylki> GetAllDelivererParcelsWithoutHistorical(int id)
        {
            var delivererSubregions = GetSubregionsForDeliverer(id);
            Statusy statusOfDeliveredParcel = GetStatusOfDeliveredParcel();
            List<Przesylki> parcels = new List<Przesylki>();

            foreach (var subregion in delivererSubregions)
            {
                var parcelsForSub = (from parcel in dbEntities.Przesylki
                                    where parcel.Status != statusOfDeliveredParcel.ID
                                    && (parcel.Klienci.Subregion == subregion.ID || parcel.Klienci1.Subregion == subregion.ID)
                                    select parcel).ToList();
                parcels.AddRange(parcelsForSub);
            }

            return parcels.Distinct().OrderBy(i => id).ToList();
        }

        public static void RemoveParcel(int id)
        {
            Przesylki przesylki = GetParcelByID(id);
            dbEntities.Przesylki.Remove(przesylki);
            dbEntities.SaveChanges();
        }

        public static void AddParcel(PrzesylkiCreateViewModel nowa)
        {
            Klienci nadawca, odbiorca;

            if (!IsCustomerInDB(nowa.NadawcaImie, nowa.NadawcaNazwisko, nowa.NadawcaAdres, nowa.NadawcaTelefon))
            {
                AddCustomer(nowa.NadawcaImie, nowa.NadawcaNazwisko, nowa.NadawcaAdres, nowa.NadawcaTelefon, nowa.NadawcaSubregion);
            }
            nadawca = GetCustomer(nowa.NadawcaImie, nowa.NadawcaNazwisko, nowa.NadawcaAdres, nowa.NadawcaTelefon);

            if (!IsCustomerInDB(nowa.OdbiorcaImie, nowa.OdbiorcaNazwisko, nowa.OdbiorcaAdres, nowa.OdbiorcaTelefon))
            {
                AddCustomer(nowa.OdbiorcaImie, nowa.OdbiorcaNazwisko, nowa.OdbiorcaAdres, nowa.OdbiorcaTelefon, nowa.OdbiorcaSubregion);
            }
            odbiorca = GetCustomer(nowa.OdbiorcaImie, nowa.OdbiorcaNazwisko, nowa.OdbiorcaAdres, nowa.OdbiorcaTelefon);

            Przesylki przesylki = new Przesylki();
            przesylki.Statusy = GetStatusByID((int)ParcelStatuses.Nowa);
            przesylki.Status = przesylki.Statusy.ID;
            przesylki.Timestamp = DateTime.Now;
            przesylki.Klienci = nadawca;
            przesylki.Nadawca = nadawca.ID;
            przesylki.Klienci1 = odbiorca;
            przesylki.Odbiorca = odbiorca.ID;

            nadawca.Subregiony = GetSubregionByID(nadawca.Subregion);
            odbiorca.Subregiony = GetSubregionByID(odbiorca.Subregion);

            przesylki.Dostawca = nadawca.Subregiony.Dostawca;
            przesylki.Dostawcy = nadawca.Subregiony.Dostawcy;
            przesylki.Magazyny = nadawca.Subregiony.Regiony.Magazyny.Single(m => m.Nazwa.Contains(nadawca.Subregiony.Nazwa));
            przesylki.Magazyn = nadawca.Subregiony.Regiony.Magazyny.Single(m => m.Nazwa.Contains(nadawca.Subregiony.Nazwa)).ID;
            nadawca.Przesylki.Add(przesylki);
            odbiorca.Przesylki1.Add(przesylki);
            dbEntities.Przesylki.Add(przesylki);
            dbEntities.SaveChanges();
        }

        public static IEnumerable<Przesylki> GetParcelsWithFiltersConditions(PrzesylkiIndexFilterViewModel przesylka)
        {
            var przesylki = GetAllParcels().ToList();
            List<Przesylki> przesylkiToLeft = new List<Przesylki>();

            ParcelFiltersNadawca(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersNadawcaRegion(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersNadawcaSubregion(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersNadawcaDostawca(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersNadawcaMagazyn(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersOdbiorca(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersOdbiorcaRegion(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersOdbiorcaSubregion(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersOdbiorcaDostawca(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersOdbiorcaMagazyn(przesylka, przesylki, przesylkiToLeft);
            ParcelFiltersStatus(przesylka, przesylki, przesylkiToLeft);

            return przesylki;
        }

        private static void UpdateParcelsAfterChangingSubregion(Dostawcy dostawca, int subregionId) 
        {
            List<Statusy> statusy = new List<Statusy>();
            statusy.AddRange(GetStatusesOfFreeParcel());
            List<Przesylki> przesylki = new List<Przesylki>();

            foreach(var status in statusy)
            {
                przesylki.AddRange(dbEntities.Przesylki.Where(p => p.Status == status.ID && (p.Klienci.Subregion == subregionId)));
            }

            foreach (var przesylka in przesylki) 
            {
                przesylka.Dostawca = dostawca.ID;
                przesylka.Dostawcy = dostawca;
            }

            dbEntities.SaveChanges();
        }

        #endregion

        #region ParcelFilters
        private static void ParcelFiltersStatus(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.Status != null && przesylka.Status != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Status == przesylka.Status)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersOdbiorcaMagazyn(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.OdbiorcaMagazyn != null && przesylka.OdbiorcaMagazyn != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    int idMagazynu = item.Klienci1.Subregiony.Regiony.Magazyny.Single(m => m.Nazwa.Contains(item.Klienci1.Subregiony.Nazwa)).ID;
                    if (idMagazynu == przesylka.OdbiorcaMagazyn)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersOdbiorcaDostawca(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.OdbiorcaDostawca != null && przesylka.OdbiorcaDostawca != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Klienci1.Subregiony.Dostawca == przesylka.OdbiorcaDostawca)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersOdbiorcaSubregion(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.OdbiorcaSubregion != null && przesylka.OdbiorcaSubregion != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Klienci1.Subregion == przesylka.OdbiorcaSubregion)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersOdbiorcaRegion(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.OdbiorcaRegion != null && przesylka.OdbiorcaRegion != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Klienci1.Subregiony.Region == przesylka.OdbiorcaRegion)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersOdbiorca(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.Odbiorca != null && przesylka.Odbiorca != 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Odbiorca == przesylka.Odbiorca)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersNadawcaMagazyn(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.NadawcaMagazyn != null && przesylka.NadawcaMagazyn != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    int idMagazynu = item.Klienci.Subregiony.Regiony.Magazyny.Single(m => m.Nazwa.Contains(item.Klienci.Subregiony.Nazwa)).ID;
                    if (idMagazynu == przesylka.NadawcaMagazyn)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersNadawcaDostawca(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.NadawcaDostawca != null && przesylka.NadawcaDostawca != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Klienci.Subregiony.Dostawca == przesylka.NadawcaDostawca)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersNadawcaSubregion(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.NadawcaSubregion != null && przesylka.NadawcaSubregion != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Klienci.Subregion == przesylka.NadawcaSubregion)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersNadawcaRegion(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.NadawcaRegion != null && przesylka.NadawcaRegion != 0 && przesylki.Count > 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Klienci.Subregiony.Region == przesylka.NadawcaRegion)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void ParcelFiltersNadawca(PrzesylkiIndexFilterViewModel przesylka, List<Przesylki> przesylki, List<Przesylki> przesylkiToLeft)
        {
            if (przesylka.Nadawca != null && przesylka.Nadawca != 0)
            {
                foreach (var item in przesylki)
                {
                    if (item.Nadawca == przesylka.Nadawca)
                    {
                        przesylkiToLeft.Add(item);
                    }
                }
                UpdateParcelsWithFilterConditionsList(przesylki, przesylkiToLeft);
            }
        }

        private static void UpdateParcelsWithFilterConditionsList(List<Przesylki> oldList, List<Przesylki> newList)
        {
            oldList.Clear();
            oldList.AddRange(newList);
            newList.Clear();
        }

        #endregion

        #region Statuses
        public static IEnumerable<Statusy> GetAllStatuses()
        {
            return dbEntities.Statusy.Select(m => m).ToList();
        }

        public static IEnumerable<SelectListItem> GetAllStatusesSelectItemList()
        {
            var statusy = GetAllStatuses();
            foreach (var item in statusy)
            {
                yield return new SelectListItem() { Text = item.Nazwa, Value = item.ID.ToString() };
            }
        }

        public static IEnumerable<Statusy> GetStatusesForSupervisor()
        {
            return dbEntities.Statusy.Where(p => p.ID == (int)ParcelStatuses.Wolna
                || p.ID == (int)ParcelStatuses.Migrowana
                || p.ID == (int)ParcelStatuses.Do_migracji).ToList();
        }

        public static IEnumerable<SelectListItem> GetStatusesSelectItemListForSupervisor()
        {
            var statusy = GetStatusesForSupervisor();
            foreach (var item in statusy)
            {
                yield return new SelectListItem() { Text = item.Nazwa, Value = item.ID.ToString() };
            }
        }

        public static Statusy GetStatusOfDeliveredParcel()
        {
            return dbEntities.Statusy.Find((int)ParcelStatuses.Doreczona);
        }

        public static IEnumerable<Statusy> GetStatusesOfFreeParcel()
        {
            return dbEntities.Statusy.Where(s => s.ID == (int)ParcelStatuses.Nowa || s.ID == (int)ParcelStatuses.Wolna);
        }

        public static Statusy GetStatusByID(int id)
        {
            return dbEntities.Statusy.Find(id);
        }

        public static void UpdateStatus(PrzesylkiChangeViewModel nowa)
        {
            Przesylki przesylki = GetParcelByID(nowa.ID);
            przesylki.Status = nowa.Status;
            przesylki.Statusy = GetStatusByID(przesylki.Status);

            /* przy zmianie statusu przesyłki przez nadzorcę magazynu zostaje przydzielony przesyłce nowy dostawca */
            przesylki.Dostawcy = przesylki.Klienci1.Subregiony.Dostawcy;
            przesylki.Dostawca = przesylki.Klienci1.Subregiony.Dostawca;
            przesylki.Magazyn = przesylki.Klienci1.Subregiony.Regiony.Magazyny.Single(m => m.Nazwa.Contains(przesylki.Klienci1.Subregiony.Nazwa)).ID;
            przesylki.Magazyny = przesylki.Klienci1.Subregiony.Regiony.Magazyny.Single(m => m.Nazwa.Contains(przesylki.Klienci1.Subregiony.Nazwa));
            //dbEntities.Entry(przesylka).State = EntityState.Modified;
            dbEntities.SaveChanges();
        }
        #endregion

        #region Customers
        private static bool IsCustomerInDB(string imie, string nazwisko, string adres, string telefon)
        {
            return GetCustomer(imie, nazwisko, adres, telefon) != null ? true : false;
        }

        private static Klienci GetCustomer(string imie, string nazwisko, string adres, string telefon)
        {
            return dbEntities.Klienci.SingleOrDefault(k => k.Imie.ToLower().Equals(imie)
                && k.Nazwisko.ToLower().Equals(nazwisko) && k.Adres.ToLower().Equals(adres)
                && k.Telefon.ToLower().Equals(telefon));
        }

        public static void AddCustomer(string imie, string nazwisko, string adres, string telefon, int subregion)
        {
            Klienci klient = new Klienci();
            klient.Imie = imie;
            klient.Nazwisko = nazwisko;
            klient.Adres = adres;
            klient.Telefon = telefon;
            klient.Subregion = subregion;
            dbEntities.Klienci.Add(klient);
            dbEntities.SaveChanges();
        }

        public static IEnumerable<Klienci> GetAllCustomers()
        {
            return dbEntities.Klienci.Select(d => d).ToList();
        }

        public static IEnumerable<SelectListItem> GetAllCustomersSelectItemList()
        {
            var klienci = GetAllCustomers();
            foreach (var item in klienci)
            {
                yield return new SelectListItem() { Text = string.Format("{0} {1}", item.Imie, item.Nazwisko), Value = item.ID.ToString() };
            }
        }
        #endregion

        #region Supervisors
        public static IEnumerable<Nadzorcy> GetAllSupervisors()
        {
            return dbEntities.Nadzorcy.Select(n => n).ToList();

        }

        public static Nadzorcy GetSupervisorByLogin(string login)
        {
            return dbEntities.Nadzorcy.SingleOrDefault(n => n.Login.ToLower().Equals(login.ToLower()));
        }

        public static bool IsTheSupervisorLoginCorrect(string login)
        {
            return GetSupervisorByLogin(login) != null ? true : false;
        }

        public static bool IsTheSupervisorPasswordCorrect(string login, string password)
        {
            return dbEntities.Nadzorcy.SingleOrDefault(n => n.Login.ToLower().Equals(login.ToLower())
                && n.Haslo.Equals(password)) != null ? true : false;
        }

        public static void UpdateSupervisor(NadzorcyViewModel nowy)
        {
            Nadzorcy nadzorca = GetSupervisorByLogin(nowy.Login);
            nadzorca.Haslo = nowy.PotwierdzoneHaslo;
            dbEntities.SaveChanges();
        }
        #endregion

        #region Regions
        public static IEnumerable<Regiony> GetAllRegions()
        {
            return dbEntities.Regiony.Select(d => d).ToList();
        }

        public static IEnumerable<SelectListItem> GetAllRegionsSelectItemList()
        {
            var regiony = GetAllRegions();
            foreach (var item in regiony)
            {
                yield return new SelectListItem() { Text = item.Nazwa, Value = item.ID.ToString() };
            }
        }
        #endregion

        #region Subregions
        public static IEnumerable<Subregiony> GetAllSubregions()
        {
            return dbEntities.Subregiony.Select(d => d).ToList();
        }

        public static IEnumerable<SelectListItem> GetAllSubregionsSelectItemList()
        {
            var subregiony = GetAllSubregions();
            foreach (var item in subregiony)
            {
                yield return new SelectListItem() { Text = item.Nazwa, Value = item.ID.ToString() };
            }
        }

        public static Subregiony GetSubregionByID(int id)
        {
            return dbEntities.Subregiony.Find(id);
        }

        public static IEnumerable<Subregiony> GetAllSubregionsForRegion(int id)
        {
            return dbEntities.Subregiony.Where(s => s.Region == id);
        }

        public static IEnumerable<Subregiony> GetSubregionsForDeliverer(int id) 
        {
            return dbEntities.Subregiony.Where(s => s.Dostawca == id);
        }

        /// <summary>
        /// Zwraca subregiony które można przydzielić dotawcy - wszystkie subregiony z regionu dostawcy
        /// do których dostawca nie jest aktualnie zapisany
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static IEnumerable<Subregiony> GetPossibleToAddSubregionsForDeliverer(int id) 
        {
            var delivererSubregions = GetSubregionsForDeliverer(id);
            List<Subregiony> subregions = new List<Subregiony>();

            if (delivererSubregions.Count() == 0) 
            {
                return GetAllSubregions();
            }
            foreach (var subregion in delivererSubregions)
            {
                var possibleSubregion = from sub in dbEntities.Subregiony
                                        where sub.Region == subregion.Region && sub.ID != subregion.ID
                                        select sub;
                subregions.AddRange(possibleSubregion);
            }

            return subregions;
        }

        public static void UpdateSubregionDeliverer(int delivererID, int subregionID) 
        {
            Subregiony subregion = GetSubregionByID(subregionID);

            subregion.Dostawca = delivererID;
            subregion.Dostawcy = GetDelivererByID(delivererID);

            // nie są zmieniane informacje o dostawcach dla aktualnie obsługiwanych przesyłek
            UpdateParcelsAfterChangingSubregion(subregion.Dostawcy, subregion.ID);
            dbEntities.SaveChanges();
        }
        #endregion

        #region Storages
        public static Magazyny GetStoragesBySubregion(Subregiony subregion)
        {
            return dbEntities.Magazyny.SingleOrDefault(m => m.Nazwa.ToLower().Contains(subregion.Nazwa.ToLower()) && m.Region == subregion.Region);
        }

        public static IEnumerable<Magazyny> GetAllStorages() 
        {
            return dbEntities.Magazyny.Select(m => m).ToList();
        }

        public static IEnumerable<SelectListItem> GetAllStoragesSelectItemList()
        {
            var magazyny = GetAllStorages();
            foreach (var item in magazyny)
            {
                yield return new SelectListItem() { Text = item.Nazwa, Value = item.ID.ToString() };
            }
        }
        #endregion

        #region Chart
        public static IEnumerable<SelectListItem> GetFilterScaleSelectListItem() 
        {
            Dictionary<FilterScale, string> scaleDictionary = new Dictionary<FilterScale,string>();
            FillFilterScaleDisctionary(scaleDictionary);

            foreach (FilterScale filter in Enum.GetValues(typeof(FilterScale)))
            {
                yield return new SelectListItem() { Text = scaleDictionary[filter], Value = ((int)filter).ToString() };
            }
        }

        private static void FillFilterScaleDisctionary(Dictionary<FilterScale, string> scaleDictionary)
        {
            scaleDictionary.Add(FilterScale.Day, "Dzień");
            scaleDictionary.Add(FilterScale.Week, "Tydzień");
            scaleDictionary.Add(FilterScale.Month, "Miesiąc");
            scaleDictionary.Add(FilterScale.Year, "Rok");
            scaleDictionary.Add(FilterScale.Sum, "Łącznie");
        }
        #endregion

        #region Statistics
        public static StatystykiViewModel LoadStatystykaViewModel()
        {
            StatystykiViewModel model = new StatystykiViewModel();
            model.LiczbaPrzesylek = Repository.GetNumberOfAllParcels();
            model.LiczbaDostarczonychPrzesylek = Repository.GetNumberOfDeliveredParcels();
            foreach(var item in Repository.GetDelivererResult(DelivererOpinion.TheBest))
            {
                model.NajwiecejPrzesylekDostawca.Add(string.Format("{0} {1} : {2}", item.Key.Imie, item.Key.Nazwisko, item.Value));
            }

            foreach(var item in Repository.GetDelivererResult(DelivererOpinion.TheWorst))
            {
                model.NajmniejPrzesylekDostawca.Add(string.Format("{0} {1} : {2}", item.Key.Imie, item.Key.Nazwisko, item.Value));
            }
            return model;
        }

        public static StatystykiViewModel GetStatystykaViewModelWithFilterConditions(StatystykiViewModel model)
        {
            if (model.ZakresStatystyka == null) 
            {
                return LoadStatystykaViewModel();
            }
            DateTime? startDate = new DateTime();
            FillDateScale(model, ref startDate);
            if (startDate == null)
            {
                return LoadStatystykaViewModel();
            }
            else 
            {
                return LoadStatystykaViewModelWithConditions(model, (DateTime)startDate);
            }
        }

        private static void FillDateScale(StatystykiViewModel model, ref DateTime? startDate)
        {
            switch ((FilterScale)model.ZakresStatystyka)
            {
                case FilterScale.Day:
                    startDate = DateTime.Today.AddHours(-23.59);
                    break;

                case FilterScale.Week:
                    startDate = DateTime.Today.AddDays(-7.0);
                    break;

                case FilterScale.Month:
                    startDate = DateTime.Today.AddDays(-30.0);
                    break;

                case FilterScale.Year:
                    startDate = DateTime.Today.AddDays(-365.0);
                    break;

                default:
                    startDate = null;
                    break;
            }
        }

        public static StatystykiViewModel LoadStatystykaViewModelWithConditions(StatystykiViewModel model, DateTime startDate)
        {
            model.NajmniejPrzesylekDostawca.Clear();
            model.NajwiecejPrzesylekDostawca.Clear();
            model.LiczbaPrzesylek = Repository.GetNumberOfParcelsWithDateConditions(startDate);
            model.LiczbaDostarczonychPrzesylek = Repository.GetNumberOfDeliveredParcelsWithDateConditions(startDate);
            foreach (var item in Repository.GetDelivererResultWithDateConditions(DelivererOpinion.TheBest, startDate))
            {
                model.NajwiecejPrzesylekDostawca.Add(string.Format("{0} {1} : {2}", item.Key.Imie, item.Key.Nazwisko, item.Value));
            }

            foreach (var item in Repository.GetDelivererResultWithDateConditions(DelivererOpinion.TheWorst, startDate))
            {
                model.NajmniejPrzesylekDostawca.Add(string.Format("{0} {1} : {2}", item.Key.Imie, item.Key.Nazwisko, item.Value));
            }
            model.ZakresStatystyki.AddRange(Repository.GetFilterScaleSelectListItem());
            model.Regiony.AddRange(Repository.GetAllRegionsSelectItemList());
            model.Subregiony.AddRange(Repository.GetAllSubregionsSelectItemList());
            model.Dostawcy.AddRange(Repository.GetAllDeliverersSelectItemList());
            model.SkalaWykresy.AddRange(Repository.GetFilterScaleSelectListItem());
            return model;
        }
        #endregion
    }
}